package com.yi.mall.factory.filter;

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yi.mall.factory.utils.JWTUtils;
import com.yi.mall.factory.utils.ResponseEnum;
import com.yi.mall.factory.utils.Result;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ShortcutConfigurable;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


import java.io.IOException;
import java.util.*;

@Component
public class LoginGatewayFilterFactory extends AbstractGatewayFilterFactory<LoginGatewayFilterFactory.Config> {
    public LoginGatewayFilterFactory() {
        super(Config.class);
    }

    public List<String> shortcutFieldOrder() {
        return Arrays.asList("patterns", "matchTrailingSlash");
    }
    // 集合短格式配置格式
    public ShortcutConfigurable.ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST_TAIL_FLAG;
    }

    @Override
    public GatewayFilter apply(final Config config) {
        return new GatewayFilter() {
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 获取请求request
                ServerHttpRequest request = exchange.getRequest();
                // 获取响应response
                ServerHttpResponse response = exchange.getResponse();
                // 获取配置的放行列表
                List<String> patterns = config.getPatterns();
                // 获取请求的path
                String path = request.getURI().getPath();
                // 放行
                for (String patteern : patterns) {
                    if (path.startsWith(patteern)) {
                        return chain.filter(exchange);
                    }
                }
                // 获取请求头
                String token = request.getHeaders().getFirst("Authorization");
                // 如果token为空，或者token过期，则返回未登录错误，否则，重新生成token，并将token返回给前端
                if (token == null) {
                    return writeResponse(response, Result.fail(ResponseEnum.USER_NOT_LOGGED_IN));
                } else if (JWTUtils.isExpired(token)) {
                    return writeResponse(response, Result.fail(ResponseEnum.PERMISSION_TOKEN_EXPIRED));
                } else {
                    // 获取用户id
                    Long id = JWTUtils.parseToken(token).get("userId", Long.class);
                    // 生成新的token
                    Map<String, Object> map = new HashMap<>();
                    map.put("userId", id);
                    String auth = JWTUtils.generateToken(map);
                    // 响应头中设置新的token
                    return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                        response.getHeaders().set("Authorization", auth);
                    }));
                }
            }
            private Mono<Void> writeResponse(ServerHttpResponse response, Result<?> responseVO) {
                response.getHeaders().setContentType(MediaType.APPLICATION_JSON);


                ObjectMapper objectMapper = new ObjectMapper();
                byte[] bytes;
                try {
                    bytes = objectMapper.writeValueAsBytes(responseVO);
                } catch (JsonProcessingException e) {
                    return response.writeWith(Mono.error(new IOException()));
                }
                return response.writeWith(Mono.just(response.bufferFactory().wrap(bytes)));
            }
        };
    }
    public static class Config {
        private List<String> patterns = new ArrayList();
        private boolean matchTrailingSlash = true;

        public Config() {
        }
        public LoginGatewayFilterFactory.Config setPatterns(List<String> patterns) {
            this.patterns = patterns;
            return this;
        }

        public List<String> getPatterns() {
            return patterns;
        }
        public boolean isMatchTrailingSlash() {
            return this.matchTrailingSlash;
        }

        public LoginGatewayFilterFactory.Config setMatchTrailingSlash(boolean matchTrailingSlash) {
            this.matchTrailingSlash = matchTrailingSlash;
            return this;
        }
    }
}
